home *** CD-ROM | disk | FTP | other *** search
- /*
- * Directory access --- The POSIX way (I hope <g>)
- *
- * Note: if you're doing something recursive, ignore
- * files "." and "..".
- *
- * W/ 1996 by Eero Tamminen, t150315@cc.tut.fi
- * Extended by Craig
- */
- #include <stdlib.h> /* memory stuff */
- #include <sys/stat.h> /* file statistics */
- #include <dirent.h> /* directory stuff */
- #include <string.h> /* string stuff */
- #include <unistd.h>
- #include "entries.h" /* directory entry stuff */
- #include "xa_defs.h"
- #include "xa_types.h"
- #include "xa_globl.h"
-
- static Lists NameList={NULL,NULL}; /* sorted name lists for listboxes */
- static Entry *EntryStart; /* first directory entry */
- static char *MemEnd; /* last allocated block */
- static int Dirs, Files; /* number of entries */
-
-
- /* get directory entry information and copy it into memory */
- static void get_stats(char *name, Entry *current)
- {
- struct stat st;
-
- /* get file information */
- if(stat(name, &st) < 0)
- {
- current->size = 0;
- current->flags = 0;
- }
- else
- {
- current->size = st.st_size;
- current->flags = 0;
-
- if (st.st_mode & S_IFLNK) /* ++cg[6/9/96]: Show sym links in entries */
- {
- current->flags |= FLAG_LINK;
- }
-
- if(S_ISDIR(st.st_mode))
- {
- current->flags |= FLAG_DIR;
- Dirs++;
- }else{
- if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) /* ++cg[6/9/96]: Show files that are executable */
- current->flags |= FLAG_EXECUTABLE;
-
- Files++;
- }
-
- /* set other flags */
- }
- /* copy dir entry name */
- strcpy((char*)(current+1), name);
- }
-
- /* read all the directory entries + handle memory allocation */
- Entry *read_entries(char *dir)
- {
- char *new_block;
- struct dirent *entry;
- Entry *current, *prev;
- int length, mem_left;
- char *olddir;
- DIR *dfd;
-
- DIAGS(("read_entries\n"));
- DIAGS(("dir=%s\n",dir));
-
- olddir = getcwd(0, PATH_MAX);
- chdir(dir);
-
- if(!(dfd = opendir(".")))
- return 0;
-
- if(!(MemEnd = malloc(BLOCK_SIZE)))
- {
- chdir(olddir);
- free(olddir);
- closedir(dfd);
- return 0;
- }
-
- *(char **)MemEnd = NULL; /* this is the first block */
- EntryStart = (Entry *)(MemEnd + sizeof(char *));
- mem_left = BLOCK_SIZE - sizeof(char *);
- current = prev = EntryStart;
- Files = Dirs = 0;
-
- while((entry = readdir(dfd)))
- {
- length = sizeof(Entry) + strlen(entry->d_name);
- length = (length + POINTER_ALIGN) & ~(POINTER_ALIGN-1);
-
- /* allocate more memory if needed */
- if(mem_left < length)
- {
- if(!(new_block = malloc(BLOCK_SIZE)))
- break; /* out of memory */
-
- *(char **)new_block = MemEnd;
- current = (Entry *)(new_block + sizeof(char *));
- mem_left = BLOCK_SIZE - sizeof(char *);
- MemEnd = new_block;
- }
- prev->next = current;
- prev = current;
- get_stats(entry->d_name, current);
- current = (Entry *)((char *)current + length);
- mem_left -= length;
- }
- prev->next = NULL;
- closedir(dfd);
- chdir(olddir);
- free(olddir);
- return EntryStart;
- }
-
- static int compare(const void *a, const void *b)
- {
- return strcmp(*(char**)a, *(char**)b);
- }
-
- /*
- Pattern matching
- - if you want better filtering of files, put the code here.....
-
- Valid patterns are:
- ? Any single char
- * A string of any char
- !X Any char except for X
- [abcd] One of (any one of a,b,c or d)
- Examples:
- * All files in dir
- a* All files begining with 'a'
- *.o All '.o' files
- *.!o All files not ending in '.o'
- !z*.? All files not starting with 'z', and having a single character extension
- *.[co] All '.o' and '.c' files
- */
- short match_pattern(char *t, char *pat)
- {
- short valid=1;
-
- while((valid)&&((*t)&&(*pat)))
- {
- switch(*pat)
- {
- case '?': /* Any character */
- t++;
- pat++;
- break;
- case '*': /* String of any character */
- pat++;
- while((*t)&&(*t!=*pat))
- t++;
- break;
- case '!': /* !X means any character but X */
- if (*t!=pat[1])
- {
- t++;
- pat+=2;
- }else{
- valid=0;
- }
- break;
- case '[': /* [<chars>] means any one of <chars> */
- while((*(++pat)!=']')&&(*t!=*pat));
-
- if (*pat==']')
- valid=0;
-
- break;
-
- default:
- if (*t==*pat)
- {
- t++;
- pat++;
- }else{
- valid=0;
- }
- break;
- }
- }
-
- if ((valid)&&(*t==*pat))
- {
- return 1;
- }else{
- return 0;
- }
- }
-
- /*
- divide directory entries into subdirectories & files and sort both
- ++cg[16/9/96]:retrofitted the pattern matching (glob) code
- */
- Lists *sort_entries(char *mask)
- {
- Entry *current = EntryStart;
- char **dirlist, **filelist;
-
- if(Dirs + Files <= 0)
- return 0;
-
- dirlist = NameList.dirs = malloc((Dirs+1) * sizeof(char*));
- if(!dirlist)
- return 0;
- filelist = NameList.files = malloc((Files+1) * sizeof(char*));
- if(!filelist)
- {
- free(dirlist);
- NameList.dirs = 0;
- return 0;
- }
-
- DIAGS(("sorting\n"));
- NameList.num_dirs=0;
- NameList.num_files=0;
-
- do
- {
- if(current->flags & FLAG_DIR)
- {
- *(dirlist++) = (char *)(current+1);
- NameList.num_dirs++;
- }else{
- if (match_pattern((char *)(current+1),mask)) /* ++cg: match the pattern */
- {
- *(filelist++) = (char *)(current+1);
- NameList.num_files++;
- }else{
- Files--;
- }
- }
- current = current->next;
- } while(current);
- *filelist = NULL;
- *dirlist = NULL;
-
- #if FILESELECTOR_QSORT
- if (Dirs)
- qsort(NameList.dirs, Dirs, sizeof(char*), compare);
- if (Files)
- qsort(NameList.files, Files, sizeof(char*), compare);
- #endif
-
- return &NameList;
- }
-
- /* free all the allocated spaces */
- void free_entries(void)
- {
- char *previous;
-
- /* free lists */
- if(NameList.dirs)
- {
- free(NameList.dirs);
- NameList.dirs = 0;
- }
- if(NameList.files)
- {
- free(NameList.files);
- NameList.files = 0;
- }
-
- /* free blocks */
- do
- {
- previous = *(char **)MemEnd;
- free(MemEnd);
- MemEnd = previous;
- } while(MemEnd);
- }
-